package rexsee.natives;

import java.io.StringReader;
import java.util.ArrayList;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.LogListeners;
import rexsee.core.browser.clazz.LogListeners.LogListener;
import rexsee.xml.XmlElement;
import android.content.Context;
import android.widget.Toast;

public class ViewParser {

	public static final String TAG_ROOT = "Views";
	public static final String ATTR_ID = "id";
	public static final String ATTR_STYLE = "style";
	public static final String ATTR_CHILDS = "childs";

	public final Context context;
	public final Browser browser;
	public final LogListener logListener;

	public final ArrayList<ViewItem> items = new ArrayList<ViewItem>();

	public ViewParser(Browser browser, LogListener logListener, String xml) {
		this.context = browser.getContext();
		this.browser = browser;
		this.logListener = logListener;
		if (xml != null && !xml.trim().equals("")) parse(xml);
	}

	private void processXmlElement(XmlElement element, ViewItem parent) {
		if (element == null || element.attributes == null || element.attributes.size() == 0) return;
		ViewItem item = new ViewItem();
		item.id = element.attributes.get(ATTR_ID);
		item.type = element.tagName;
		item.style = element.attributes.get(ATTR_STYLE);
		String childs = element.attributes.get(ATTR_CHILDS);
		if (childs != null && childs.trim().length() > 0) {
			item.childs = childs;
		}
		items.add(item);
		if (parent != null) parent.addChild(item.id);
		if (element.childs != null && element.childs.size() > 0) {
			for (int i = 0; i < element.childs.size(); i++) {
				processXmlElement(element.childs.get(i), item);
			}
		}
	}

	public ViewParser parse(final String mXmlContent) {

		if (mXmlContent == null || mXmlContent.trim().equals("")) {
			error("Null xml data.");
			return null;
		}

		try {

			XmlPullParserFactory factory;
			try {
				factory = XmlPullParserFactory.newInstance();
			} catch (XmlPullParserException e) {
				error(e.getLocalizedMessage());
				return null;
			}
			XmlPullParser xpp;
			try {
				xpp = factory.newPullParser();
			} catch (XmlPullParserException e) {
				error(e.getLocalizedMessage());
				return null;
			}
			try {
				xpp.setInput(new StringReader(mXmlContent));
			} catch (XmlPullParserException e) {
				error(e.getLocalizedMessage());
				return null;
			}
			int eventType;
			try {
				eventType = xpp.getEventType();
			} catch (XmlPullParserException e) {
				error(e.getLocalizedMessage());
				return null;
			}

			XmlElement root = new XmlElement(null, "XML", 0, "root");

			XmlElement current = root;
			while (eventType != XmlPullParser.END_DOCUMENT) {
				if (eventType == XmlPullParser.START_TAG) {
					String tagName = xpp.getName().toLowerCase();
					XmlElement e = new XmlElement(current, tagName, current.depth + 1, "tag");
					int count = xpp.getAttributeCount();
					for (int i = 0; i < count; i++) {
						String name = xpp.getAttributeName(i);
						String value = xpp.getAttributeValue(i);
						e.addAttribute(name.toLowerCase(), value);
					}
					current.addChild(e);
					current = e;
				} else if (eventType == XmlPullParser.END_TAG) {
					current = current.parent;
				} else if (eventType == XmlPullParser.TEXT) {
					String t = xpp.getText().replaceAll("\\s", "");
					if (t.length() > 0) {
						XmlElement e = new XmlElement(current, "", current.depth + 1, "text");
						e.text = t;
						current.addChild(e);
					}
				}
				try {
					eventType = xpp.nextToken();
				} catch (Exception e) {
					error(e.getLocalizedMessage());
					return null;
				}
			}

			XmlElement window = root.childs.get(0);
			if (window == null || !window.tagName.equalsIgnoreCase(TAG_ROOT)) {
				error("Root tag not found.");
				return null;
			}
			if (window.childs == null || window.childs.size() == 0) {
				error("Root element has no child.");
				return null;
			}

			for (int i = 0; i < window.childs.size(); i++) {
				processXmlElement(window.childs.get(i), null);
			}

			return this;

		} catch (Exception e) {

			error(e.getLocalizedMessage());
			return null;

		} catch (OutOfMemoryError oom) {

			error("Out of memory.");
			return null;

		}

	}

	public void error(String message) {
		message = "[" + this.getClass().getName() + ".parser]" + message;
		logListener.run(context, browser, LogListeners.LOG_TYPE_ERROR, message);
		Toast.makeText(browser.getContext(), message, Toast.LENGTH_SHORT).show();
		browser.progressDialog.hide();
	}

	public static class ViewItem {
		public String id = null;
		public String type = null;
		public String style = "";
		public String childs = "";
		public boolean isNull() {
			return id == null || type == null;
		}
		public boolean hasChild() {
			return !childs.trim().equals("");
		}
		public void addChild(String child) {
			if (hasChild()) childs += "|" + child;
			else childs = child;
		}
	}

}
